#include "ClientManager.h"
using namespace std;




ClientManager::ClientManager(Socket *sock, list<Circuito*>* lista, Mutex& mutexLista):mutex_lista(mutexLista)
{
	this->socket=sock;
	this->lista_circuitos=lista;
}


void* ClientManager:: run(){

	Busy(true);
	//recibo la orden dentro de un soap
	std::string stream;
	Recive(stream);
	std::string circuito, orden,entradas;

	//este parsearMsj ahora toma el msj en soap y le saca el envoltorio
	this->parsear_msj_soap(stream,circuito,orden,entradas);

	//busco en la lista el nombre de archivo en la lista, si no esta la cargo en memoria
	Circuito* circuito_actual;
	ParserXml xml;
	std::list<Circuito*>::const_iterator lit(lista_circuitos->begin());
	std::list<Circuito*>::const_iterator lend(lista_circuitos->end());
	int encontrado=0;

	//Como la lista es un recurso compartido por los cliente manager la protejo
	this->mutex_lista.lock();
	if(!lista_circuitos->empty()){
		while((!encontrado) && (lit!=lend)){
			if((*(lit))->get_nombre()==circuito)
				encontrado=1;
			else
				++lit;
		}
		if(encontrado)
			circuito_actual= *lit;
	}
	if(!encontrado){
		//levanto a memoria el circuito con ese nombre
		std::list<Compuerta*> * pListaCompuertas;
		std::list<Entrada*> * pListaEntradas;
		std::list<Salida*> * pListaSalidas;

		std::list<Cable*>* pListaCables;
		std::string * nombre = new std::string;

		pListaCompuertas = new std::list<Compuerta*>;
		pListaEntradas = new std::list<Entrada*>;
		pListaSalidas = new std::list<Salida*>;

		pListaCables = new std::list<Cable*>;

		std::list<ElementoExterno*>* pListaExternos;
		pListaExternos = new std::list<ElementoExterno*>;

		if((xml.obtener_Desde_Archivo((char*)circuito.c_str(), pListaCompuertas,pListaEntradas,pListaSalidas, pListaCables
				, pListaExternos, nombre)) != -1){

				circuito_actual = new Circuito (pListaEntradas, pListaSalidas, pListaCompuertas, pListaCables,pListaExternos, *nombre);


				this->lista_circuitos->push_back(circuito_actual);
		}
		else  circuito_actual = NULL;
	}
	//libero el mutex, termine de trabajar con la lista
	this->mutex_lista.unlock();

	//luego con ese puntero en mano realizo las operaciones pertinentes.
	if(circuito_actual!=NULL){
		if(orden=="data"){
			this->enviar_data(circuito_actual);
		}

		else if(orden=="ver"){
			this->enviar_circuito(circuito) ;
		}

		else if(orden=="simular"){
			this->enviar_simulacion(circuito_actual, entradas);

		}
	}
	cerr<<"Desconectando Cliente... "<<endl;
	this->Shutdown(2);
	this->Close();
	delete socket;// libera la memoria del socket que le paso el servidor
	Busy(false);	
	//pthread_exit(NULL);
	return(void*)0;
}

int ClientManager:: enviar_simulacion(Circuito* circuito_actual,std::string stream){

	empaquetadorSoap soap;
	xmlDocPtr doc;
	//pido la lista de entradas
	//le envio un send para q me mande las entradas

	//recorro la lista seteando los valores con lo q me devolvio en el string

	//simulo una vez
	//devuelvo un string dentro de un SOAP con el resultado ese
	std::list<Entrada*> l_entradas = circuito_actual->get_lista_entradas();
	if(!l_entradas.empty()){
		std::list<Entrada*>::iterator it = l_entradas.begin();

		for(unsigned int i=0; i< stream.size(); i++){
			 if(stream[i] != '0') (*it)->set_estado(true);
			 else (*it)->set_estado(false);
			 it++;
		}

		//envio el resultado de la simulacion del circuito

		std::string resultado= circuito_actual->simular_una_vez();

		doc = soap.empaquetar_resultado_simulacion(resultado);
		char * linea[10000];
		int * pi = new int(10000);
		xmlDocDumpMemory (doc, (xmlChar**)linea, pi);
		std::string l_cadena(*linea);

		if (*linea!= NULL)
				Send((char*)l_cadena.c_str());
		return 1;
	}
	return 0;
}

int ClientManager:: enviar_circuito(std::string circuito){

	empaquetadorSoap pSOAP;
	xmlDocPtr doc;

	char * ruta = (char*)circuito.c_str();
	doc = pSOAP.empaquetar(ruta);

	char * linea[10000];

	int * pi = new int(10000);
	//levanto el xml a una buffer para pasarlo por el socket
	xmlDocDumpMemory (doc, (xmlChar**)linea, pi);

	std::string l_cadena(*linea);
	if (*linea!= NULL){

		Send((char*)l_cadena.c_str());
	}
	return 1;

}

int ClientManager::enviar_data(Circuito* circuito_actual){
	empaquetadorSoap soap;
	xmlDocPtr doc;

	if(circuito_actual != NULL){

		doc = soap.empaquetar_datos_entrada_salida(circuito_actual->get_lista_entradas().size(),circuito_actual->get_lista_salidas().size());
		char * linea[100];
		int * pi = new int(100);
		//levanto el xml a una buffer para pasarlo por el socket
		xmlDocDumpMemory (doc, (xmlChar**)linea, pi);
		std::string l_cadena(*linea);

		std::cerr << "estaria enviando " << l_cadena.c_str() <<std::endl;

		if (*linea!= NULL){
			Send((char*)l_cadena.c_str());

		}
	}
	else {
		this->Close();
		std::cerr << "circuito vacio " << std::endl;
	}
	return 0;
}


int ClientManager:: ParsearMsj(string stream, string& circuito, string& orden){

	//aca lo q hago es levantar el msj soap y sacar la informacion que requiero
	//tengo q agregar un campo por si es obtener salidas

	unsigned int pos, posEnd;
	//Checkeo que el mensaje entrante tenga una barra intermedio
	if((pos=stream.find_first_of ('|', 0 ))==string::npos)
		return -1;
	posEnd=stream.find_first_of ( '\n', 0 );
	circuito=stream.substr ( 0, pos );
	orden=stream.substr ( pos+1, posEnd );
	return 0;

}



int ClientManager:: parsear_msj_soap(std::string msj, std::string& circuito,
											std::string& orden, std::string& entradas){
//stream tendria el soap

	//aca lo q hago es levantar el msj soap y sacar la informacion que requiero
	DesempaquetadorSoap desSoap;
	xmlDocPtr docSoap;
	docSoap = xmlParseMemory ((char*)msj.c_str(), msj.size());
	//si tengo error al parsear devuelvo 0
	if(docSoap == NULL)	return 0;

	desSoap.obtener_orden_a_realizar(docSoap,circuito,orden,entradas);
	//Checkeo que el mensaje entrante tenga una barra intermedio
	//std::cerr<<"Circuito:" << circuito << " Orden" << orden << " entradas" << entradas <<std::endl;

	return 1;

}


int ClientManager:: SendError(){

	Send((char*)"ERROR\n");
	Shutdown(2);
	Close();
	return -1;
}

//*------------------------*//
//*Metodos de Comunicacion *//
//*------------------------*//

int ClientManager::Shutdown(int how){
	return(socket->shutdown(how));
}

int ClientManager::Close(){
	return(socket->close());
}

int ClientManager::Recive(std::string& stream){
	return socket->recvtimeout(stream);
}

int ClientManager::Send(char* msj){
	int len;
	len=strlen(msj);
	return(socket->send(msj, len));
}
